package com.xtx.json;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * A JsonObject is an unordered collection of name/value pairs.
 * 
 * @author JSON.org
 * @author Chenin
 * @version 2007-1-17
 */
@SuppressWarnings("unchecked")
public class JsonObject implements Serializable, JsonEntity, Map {
    private static final long serialVersionUID = -393221658263408183L;

    /**
     * The hash map where the JsonObject's properties are kept.
     */
    private Map object;

    /**
     * Construct an empty JsonObject.
     */
    public JsonObject() {
        this.object = new HashMap();
    }

    public JsonObject(Map object) {
        this.object = object;
    }

    /**
     * Construct a JsonObject from a JsonTokener.
     * 
     * @param tokener A JsonTokener object containing the source string
     * @throws JsonException If there is a syntax error in the source string
     */
    public JsonObject(JsonTokener tokener) throws JsonException {
        this();
        char chr;
        String key;
        if (tokener.nextClean() != '{') {
            throw new JsonException("A JSON Object text must begin with '{'");
        }
        while (true) {
            chr = tokener.nextClean();
            switch (chr) {
                case 0:
                    throw new JsonException("A JSON Object text must end with '}'");
                case '}':
                    return;
                default:
                    tokener.back();
                    key = tokener.nextValue().toString();
            }
            /*
             * The key is followed by ':'. We will also tolerate '=' or '=>'.
             */
            chr = tokener.nextClean();
            if (chr == '=') {
                if (tokener.next() != '>') {
                    tokener.back();
                }
            } else if (chr != ':') {
                throw new JsonException("Expected a ':' after a key");
            }
            this.put(key, tokener.nextValue());
            /*
             * Pairs are separated by ','. We will also tolerate ';'.
             */
            switch (tokener.nextClean()) {
                case ';':
                case ',':
                    if (tokener.nextClean() == '}') {
                        return;
                    }
                    tokener.back();
                    break;
                case '}':
                    return;
                default:
                    throw new JsonException("Expected a ',' or '}'");
            }
        }
    }

    public String toJsonString() {
        StringBuffer strb = new StringBuffer();
        strb.append('{');
        Iterator keys = this.object.keySet().iterator();
        while (keys.hasNext()) {
            Object key = keys.next();
            if (strb.length() > 1) {
                strb.append(',');
            }
            strb.append(JsonPrinter.toQuote(key == null ? "null" : key.toString()));
            strb.append(":");
            strb.append(JsonPrinter.getString(this.object.get(key)));
        }
        strb.append('}');
        return strb.toString();
    }

    public String toString() {
        return this.toJsonString();
    }

    public void clear() {
        this.object.clear();
    }

    public boolean containsKey(Object key) {
        return this.object.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return this.object.containsValue(value);
    }

    public Set entrySet() {
        return this.object.entrySet();
    }

    public Object get(Object key) {
        return this.object.get(key);
    }

    public boolean isEmpty() {
        return this.object.isEmpty();
    }

    public Set keySet() {
        return this.object.keySet();
    }

    public Object put(Object key, Object value) {
        return this.object.put(key, value);
    }

    public void putAll(Map m) {
        this.object.putAll(m);
    }

    public Object remove(Object key) {
        return this.object.remove(key);
    }

    public int size() {
        return this.object.size();
    }

    public Collection values() {
        return this.object.values();
    }
}
